﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using OpenLS.Drawing;

namespace OpenLS.Spreadsheet.UI
{
    class BordersFormatter : FormatterBase
    {
        private readonly ColorScheme _colorScheme;
      
        public BordersFormatter(Range range)
        {
            _colorScheme = range.Worksheet.Workbook.Theme.ColorScheme;
            foreach (var borderType in GetBorderTypes())
            {
                bool uniform;
                try
                {
                    var border = range.GetBorder(borderType, out uniform);
                    if (!uniform)
                    {
                        Items.Add(new BorderFormatter(BorderStyle.None, SpreadsheetColors.Black, borderType,
                                                      _colorScheme, BorderFormatter.State.NonUniform));
                    }
                    else if (border != null)
                    {
                        Items.Add(new BorderFormatter(border.Style, border.Color, borderType, _colorScheme, BorderFormatter.State.Enabled));
                    }
                }
                catch
                {
                }
            }
            var styles  = Enumerable.ToList(Enumerable.Distinct(Enumerable.Select(Items, f => f.BorderStyle)));
            if (styles.Count == 1)
                this.BorderStyle = styles[0];
            var colors = Enumerable.ToList(Enumerable.Distinct(Enumerable.Select(Items, f => f.Color)));
            if (colors.Count == 1)
                this.Color = colors[0]; 
            RefreshLines();
        }
        IEnumerable<BorderType> GetBorderTypes()
        {
            yield return BorderType.LeftEdge;
            yield return BorderType.RightEdge;
            yield return BorderType.TopEdge;
            yield return BorderType.BottomEdge;
            yield return BorderType.InsideHorizontal;
            yield return BorderType.InsideVertical;
            yield return BorderType.DiagonalDown;
            yield return BorderType.DiagonalUp;
        }

        private bool removeAll = false;

        private BorderStyle _borderStyle = BorderStyle.Thin;
        public BorderStyle BorderStyle
        {
            get { return _borderStyle; }
            set { _borderStyle = value; }
        }

        private SpreadsheetColor _color = new RgbColor(Colors.Black);
        public SpreadsheetColor Color
        {
            get { return _color; }
            set { _color = value; }
        }
        public ICommand ToggleBorderCommand { get { return new DelegatingCommand(OnToggleBorder); } }
        public ICommand NoBorderCommand { get { return new DelegatingCommand(OnNoBorder); } }

        private void OnNoBorder(object obj)
        {
            SetDirty2();
            foreach (var item in Items)
            {
                item.LineState = BorderFormatter.State.Disabled;
            }
            removeAll = true;
        }

        public ICommand OutlineBorderCommand { get { return new DelegatingCommand(OnOutlineBorder); } }

        private void OnOutlineBorder(object obj)
        {
            SetDirty2();
            AddItems(outsideBorderTypes());
            RefreshLines();
            
        }

        private void AddItems(IEnumerable<BorderType> types)
        {
            foreach (BorderType  type in types)
            {
                var item = Enumerable.FirstOrDefault(Items, i => i.BorderType == type);
                if (item != null)
                    Items.Remove(item);
                item = new BorderFormatter(this.BorderStyle, this.Color, type, _colorScheme, BorderFormatter.State.Enabled);
                Items.Add(item);
            }
        }

        private IEnumerable<BorderType> outsideBorderTypes()
        {
            yield return BorderType.LeftEdge;
            yield return BorderType.RightEdge;
            yield return BorderType.TopEdge;
            yield return BorderType.BottomEdge;
        }
        private IEnumerable<BorderType> insideBorderTypes()
        {
            yield return BorderType.InsideVertical;
            yield return BorderType.InsideHorizontal;
        }

        internal void SetDirty2()
        {
            removeAll = false;
            base.SetDirty();
        }

        public ICommand InsideBorderCommand { get { return new DelegatingCommand(OnInsideBorder); } }

        private void OnInsideBorder(object obj)
        {
            SetDirty2();
            AddItems(insideBorderTypes());
            RefreshLines();
           
        }

        private void OnToggleBorder(object obj)
        {
            SetDirty2();
            BorderType type = (BorderType) obj;
            var item = Enumerable.FirstOrDefault(Items, i => i.BorderType == type);
            bool noAdd = false;
            if (item != null)
            {
                switch (item.LineState)
                {
                    case BorderFormatter.State.Enabled:
                        if (item.Compatible(this))
                        {
                            item.LineState = BorderFormatter.State.Disabled;
                            noAdd = true;
                        }
                        else
                        {
                            Items.Remove(item);
                        }
                        break;

                        case BorderFormatter.State.Disabled:
                        Items.Remove(item);
                        break;
                    case BorderFormatter.State.NonUniform:
                        Items.Remove(item);
                        break;
                    default:
                        throw new NotSupportedException();
                }
               
            }
            if (!noAdd)
            {
                item = new BorderFormatter(this.BorderStyle, this.Color, type, _colorScheme, BorderFormatter.State.Enabled);
                Items.Add(item);
            }
            RefreshLines();
        }

        private readonly ObservableCollection<BorderFormatter> _items = new ObservableCollection<BorderFormatter>();
        public ObservableCollection<BorderFormatter> Items
        {
            get { return _items; }
           
        }

        private readonly ObservableCollection<Line> _lines = new ObservableCollection<Line>();
        public ObservableCollection<Line> Lines
        {
            get { return _lines; }
        }
        void RefreshLines()
        {
            
            Lines.Clear();
            foreach (var line in Enumerable.Select (this.Items, item => item.Line))
            {
                Lines.Add(line);
            }
        }
        protected override void ApplyOverride(Range selection)
        {
            if (removeAll)
            {
                selection.ClearBorders();
                return;
            }
            foreach (var item in Items)
            {
                item.Apply(selection);
            }
        }
    }
}